001    /*
002     * Copyright 2005 Stephen J. McConnell.
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.transit.console;
020    
021    import java.io.IOException;
022    import java.io.OutputStream;
023    import java.io.File;
024    import java.io.FileNotFoundException;
025    import java.lang.reflect.InvocationTargetException;
026    import java.net.URI;
027    import java.net.URL;
028    import java.util.List;
029    import java.util.Set;
030    import java.util.HashSet;
031    
032    import net.dpml.cli.Option;
033    import net.dpml.cli.Group;
034    import net.dpml.cli.CommandLine;
035    import net.dpml.cli.commandline.Parser;
036    import net.dpml.cli.util.HelpFormatter;
037    import net.dpml.cli.OptionException;
038    import net.dpml.cli.DisplaySetting;
039    import net.dpml.cli.builder.ArgumentBuilder;
040    import net.dpml.cli.builder.GroupBuilder;
041    import net.dpml.cli.builder.DefaultOptionBuilder;
042    import net.dpml.cli.builder.CommandBuilder;
043    import net.dpml.cli.validation.URIValidator;
044    import net.dpml.cli.validation.URLValidator;
045    import net.dpml.cli.validation.NumberValidator;
046    
047    import net.dpml.util.Logger;
048    import net.dpml.lang.UnknownKeyException;
049    import net.dpml.lang.ValueDirective;
050    
051    import net.dpml.lang.Part;
052    import net.dpml.lang.PartException;
053    
054    import net.dpml.transit.Artifact;
055    import net.dpml.transit.Transit;
056    import net.dpml.transit.TransitBuilder;
057    import net.dpml.transit.DefaultTransitModel;
058    import net.dpml.transit.info.TransitDirective;
059    import net.dpml.transit.info.ProxyDirective;
060    import net.dpml.transit.info.CacheDirective;
061    import net.dpml.transit.info.HostDirective;
062    import net.dpml.transit.info.LayoutDirective;
063    import net.dpml.util.ExceptionHelper;
064    
065    
066    /**
067     * Transit Plugin that provides support for the configuration of the Transit subsystem.
068     *
069     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
070     * @version 1.0.2
071     */
072    public class TransitConsoleHandler 
073    {
074        // ------------------------------------------------------------------------
075        // state
076        // ------------------------------------------------------------------------
077    
078        private final Logger m_logger;
079        private final TransitDirective m_directive;
080        private final CommandLine m_line;
081        private final TransitDirectiveBuilder m_builder;
082        
083        // ------------------------------------------------------------------------
084        // constructor
085        // ------------------------------------------------------------------------
086    
087       /**
088        * Creation of a new Transit CLI handler.
089        * 
090        * @param logger the assigned logging channel
091        * @param args command line arguments
092        * @exception Exception if an error occurs during plugin establishment
093        */
094        public TransitConsoleHandler( Logger logger, String[] args ) throws Exception
095        {
096            this( logger, getCommandLine( logger, args ) );
097        }
098        
099       /**
100        * Creation of a new Transit CLI handler.
101        *
102        * @param logger the assigned logging channel
103        * @param line the command line
104        * @exception Exception if an error occurs during plugin establishment
105        */
106        private TransitConsoleHandler( final Logger logger, final CommandLine line ) throws Exception
107        {
108            if( null == line ) 
109            {
110                m_line = null;
111                m_directive = null;
112                m_builder = null;
113                m_logger = null;
114                System.exit( -1 );
115            }
116            else
117            {
118                m_logger = logger;
119                m_line = line;
120                m_directive = loadTransitDirective( line );
121                m_builder = new TransitDirectiveBuilder( m_directive );
122                if( null == m_directive )
123                {
124                    System.exit( -1 );
125                }
126            }
127            
128            // handle command
129            
130            if( line.hasOption( INFO_COMMAND ) )
131            {
132                processInfo( line );
133            }
134            else if( line.hasOption( ADD_COMMAND ) )
135            {
136                TransitDirective directive = processAdd( line );
137                export( directive );
138            }
139            else if( line.hasOption( SET_COMMAND ) )
140            {
141                TransitDirective directive = processSet( line );
142                export( directive );
143            }
144            else if( line.hasOption( REMOVE_COMMAND ) )
145            {
146                TransitDirective directive = processRemove( line );
147                export( directive );
148            }
149            else if( line.hasOption( REVERT_COMMAND ) )
150            {
151                export( TransitDirective.CLASSIC_PROFILE );
152            }
153            else if( line.hasOption( LOAD_COMMAND ) )
154            {
155                processLoad( line );
156            }
157            else
158            {
159                processHelp();
160            }
161        }
162        
163        // ------------------------------------------------------------------------
164        // command handling
165        // ------------------------------------------------------------------------
166        
167        private void processLoad( CommandLine line )
168        {
169            try
170            {
171                URI uri = (URI) line.getValue( LOAD_COMMAND, null );
172                List list = line.getValues( ARGUMENTS );
173                String[] args = (String[]) list.toArray( new String[ list.size() ] );
174                Part part = Part.load( uri );
175                Object instance = part.instantiate( new Object[]{args, m_logger} );
176                if( instance instanceof Runnable )
177                {
178                    Runnable runnable = (Runnable) instance;
179                    runnable.run();
180                }
181            }
182            catch( PartException e )
183            {
184                boolean stack = isDebugEnabled();
185                String message = ExceptionHelper.packException( e, stack ); 
186                System.out.println( message );
187            }
188            catch( Throwable e )
189            {
190                processException( e );
191            }
192        }
193        
194        private void processException( Throwable e )
195        {
196            if( e instanceof InvocationTargetException )
197            {
198                InvocationTargetException ite = (InvocationTargetException) e;
199                Throwable cause = ite.getCause();
200                processException( cause );
201            }
202            else
203            {
204                final String error = 
205                  "Part exception.";
206                String message = ExceptionHelper.packException( error, e, true ); 
207                System.out.println( message );
208            }
209        }
210        
211        private boolean isDebugEnabled()
212        {
213            return "true".equals( System.getProperty( "dpml.debug", "false" ) );
214        }
215        
216        private void processInfo( CommandLine line )
217        {
218            StringBuffer buffer = new StringBuffer();
219            
220            buffer.append( "\n\n  Transit Console Version 1.0.2" );
221            buffer.append( "\n  Transit Runtime Version " + Transit.VERSION );
222            buffer.append( "\n\n  Environment\n" );
223            buffer.append( "\n    ${dpml.home} \t" + Transit.DPML_HOME );
224            buffer.append( "\n    ${dpml.data} \t" + Transit.DPML_DATA );
225            buffer.append( "\n    ${dpml.prefs} \t" + Transit.DPML_PREFS );
226            buffer.append( "\n    ${dpml.system} \t" + Transit.DPML_SYSTEM );
227            
228            ProxyDirective proxy = m_directive.getProxyDirective();
229            if( null != proxy )
230            {
231                buffer.append( "\n\n  Proxy Settings" );
232                buffer.append( "\n\n    Host: \t" + proxy.getHost() );
233                if( proxy.getUsername() != null )
234                {
235                    buffer.append( "\n    Username: \t" + proxy.getUsername() );
236                }
237                char[] pswd = proxy.getPassword();
238                if( null != pswd )
239                {
240                    buffer.append( "\n    Password: \t" );
241                    for( int i=0; i<pswd.length; i++ )
242                    {
243                        buffer.append( "*" );
244                    }
245                }
246                String[] excludes = proxy.getExcludes();
247                if( excludes.length > 0 )
248                {
249                    buffer.append( "\n    Excludes: \t" );
250                    for( int i=0; i<excludes.length; i++ )
251                    {
252                        String exclude = excludes[i];
253                        buffer.append( exclude );
254                        if( i < ( excludes.length-1 ) )
255                        {
256                            buffer.append( ", " );
257                        }
258                    }
259                }
260            }
261            
262            CacheDirective cache = m_directive.getCacheDirective();
263            
264            buffer.append( "\n\n  Cache and System Settings\n" );
265            buffer.append( "\n    Cache Layout: \t" + cache.getCacheLayout() );
266            buffer.append( "\n    Cache Directory: \t" + cache.getCache() );
267            buffer.append( "\n    System Directory: \t" + cache.getLocal() );
268            buffer.append( "\n    System Layout: \t" + cache.getLocalLayout() );
269            
270            HostDirective[] hosts = cache.getHostDirectives();
271            if( hosts.length > 0 )
272            {
273                buffer.append( "\n\n  Host Settings" );
274                for( int i=0; i<hosts.length; i++ )
275                {
276                    HostDirective host = hosts[i];
277                    buffer.append( "\n\n    " + host.getID() + " (" + ( i+1 ) + ")" );
278                    buffer.append( "\n\n      URL\t" + host.getHost() );
279                    buffer.append( "\n      Priority:\t" + host.getPriority() );
280                    if( host.getIndex() != null )
281                    {
282                        buffer.append( "\n      Index: \t" + host.getIndex() );
283                    }
284                    buffer.append( "\n      Enabled: \t" + host.getEnabled() );
285                    buffer.append( "\n      Trusted: \t" + host.getTrusted() );
286                    buffer.append( "\n      Layout: \t" + host.getLayout() );
287                    if( host.getUsername() != null )
288                    {
289                        buffer.append( "\n      Username: \t" + host.getUsername() );
290                    }
291                    buffer.append( "\n      Password: \t" );
292                    char[] pswd = host.getPassword();
293                    if( null != pswd )
294                    {
295                        for( int j=0; j<pswd.length; j++ )
296                        {
297                            buffer.append( "*" );
298                        }
299                    }
300                    buffer.append( "\n      Prompt: \t" + host.getPrompt() );
301                    buffer.append( "\n      Scheme: \t" + host.getScheme() );
302                }
303            }
304            else
305            {
306                buffer.append( "\n\n  No hosts." );
307            }
308            
309            LayoutDirective[] layouts = cache.getLayoutDirectives();
310            if( layouts.length > 0 )
311            {
312                buffer.append( "\n\n  Layout Settings" );
313                for( int i=0; i<layouts.length; i++ )
314                {
315                    LayoutDirective layout = layouts[i];
316                    buffer.append( "\n\n    " + layout.getID() + " (" + ( i+1 ) + ")" );
317                    buffer.append( "\n\n      Codebase:\t" + layout.getCodeBaseURI() );
318                    buffer.append( "\n      Title:\t" + layout.getTitle() );
319                }
320            }
321            
322            System.out.println( buffer.toString() );
323        }
324        
325        private TransitDirective processAdd( CommandLine line ) throws Exception
326        {
327            if( line.hasOption( ADD_HOST_COMMAND ) )
328            {
329                String key = (String) line.getValue( ADD_HOST_COMMAND, null );
330                CacheDirective cache = m_directive.getCacheDirective();
331                HostDirective[] hosts = cache.getHostDirectives();
332                for( int i=0; i<hosts.length; i++ )
333                {
334                    HostDirective h = hosts[i];
335                    if( h.getID().equals( key ) )
336                    {
337                        System.out.println( "ERROR: Host id '" + key + "' already assigned." );
338                        return null;
339                    }
340                }
341                
342                System.out.println( "Adding host: " + key );
343                URL url = (URL) line.getValue( REQUIRED_HOST_OPTION, null );
344                String username = (String) line.getValue( USERNAME_OPTION, null );
345                String password = (String) line.getValue( PASSWORD_OPTION, null );
346                Number priority = (Number) line.getValue( HOST_PRIORITY_OPTION, new Integer( 100 ) );
347                String index = (String) line.getValue( HOST_INDEX_OPTION, null );
348                boolean enabled = !line.hasOption( DISABLED_OPTION );
349                boolean trusted = line.hasOption( TRUSTED_OPTION );
350                String layout = (String) line.getValue( LAYOUT_OPTION, "classic" );
351                String scheme = (String) line.getValue( HOST_SCHEME_OPTION, "" );
352                String prompt = (String) line.getValue( HOST_PROMPT_OPTION, "" );
353                
354                HostDirective host = 
355                  new HostDirective( 
356                    key, priority.intValue(), url.toString(), index, username, 
357                    toCharArray( password ), enabled, trusted, layout, 
358                    scheme, prompt );
359                    
360                HostDirective[] newHosts = new HostDirective[ hosts.length + 1 ];
361                for( int i=0; i<hosts.length; i++ )
362                {
363                    newHosts[i] = hosts[i];
364                }
365                newHosts[ hosts.length ] = host;
366                CacheDirectiveBuilder builder = new CacheDirectiveBuilder( cache );
367                CacheDirective newCache = builder.create( newHosts );
368                return m_builder.create( newCache );
369            }
370            else if( line.hasOption( ADD_LAYOUT_COMMAND ) )
371            {
372                String key = (String) line.getValue( ADD_LAYOUT_COMMAND, null );
373                CacheDirective cache = m_directive.getCacheDirective();
374                LayoutDirective[] handlers = cache.getLayoutDirectives();
375                for( int i=0; i<handlers.length; i++ )
376                {
377                    LayoutDirective c = handlers[i];
378                    if( c.getID().equals( key ) )
379                    {
380                        System.out.println( "ERROR: Layout id '" + key + "' already assigned." );
381                        return null;
382                    }
383                }
384                
385                System.out.println( "Adding layout: " + key );
386                URI uri = (URI) line.getValue( REQUIRED_CODEBASE_OPTION, null );
387                String title = (String) line.getValue( TITLE_OPTION, null );
388                
389                LayoutDirective handler = 
390                  new LayoutDirective( 
391                    key, title, uri, new ValueDirective[0] );
392                
393                LayoutDirective[] newHandlers = new LayoutDirective[ handlers.length + 1 ];
394                for( int i=0; i<handlers.length; i++ )
395                {
396                    newHandlers[i] = handlers[i];
397                }
398                newHandlers[ handlers.length ] = handler;
399                CacheDirectiveBuilder builder = new CacheDirectiveBuilder( cache );
400                CacheDirective newCache = builder.create( newHandlers );
401                return m_builder.create( newCache );
402            }
403            else
404            {
405                throw new IllegalStateException( "Unqualified add." );
406            }
407        }
408        
409        private TransitDirective processSet( CommandLine line ) throws Exception
410        {
411            if( line.hasOption( SET_CACHE_COMMAND ) )
412            {
413                return setCache( line );
414            }
415            else if( line.hasOption( SET_SYSTEM_COMMAND ) )
416            {
417                return setSystem( line );
418            }
419            else if( line.hasOption( PROXY_COMMAND ) )
420            {
421                return setProxy( line );
422            }
423            else if( line.hasOption( SET_HOST_COMMAND ) )
424            {
425                return setHost( line );
426            }
427            else if( line.hasOption( SET_LAYOUT_COMMAND ) )
428            {
429                return setLayout( line );
430            }
431            else
432            {
433                throw new IllegalStateException( "Unqualified set command." );
434            }
435        }
436        
437        private TransitDirective setCache( CommandLine line ) throws Exception
438        {
439            String cache = (String) line.getValue( DIRECTORY_OPTION );
440            String layout = (String) line.getValue( LAYOUT_OPTION );
441            CacheDirective directive = m_directive.getCacheDirective();
442            CacheDirectiveBuilder builder = new CacheDirectiveBuilder( directive );
443            CacheDirective newCache = builder.create( cache, layout, null, null );
444            return m_builder.create( newCache );
445        }
446        
447        private TransitDirective setSystem( CommandLine line ) throws Exception
448        {
449            String system = (String) line.getValue( DIRECTORY_OPTION );
450            String layout = (String) line.getValue( LAYOUT_OPTION );
451            CacheDirective directive = m_directive.getCacheDirective();
452            CacheDirectiveBuilder builder = new CacheDirectiveBuilder( directive );
453            CacheDirective newCache = builder.create( null, null, system, layout );
454            return m_builder.create( newCache );
455        }
456        
457        private TransitDirective setProxy( CommandLine line ) throws Exception
458        {
459            System.out.println( "Updating proxy configuration." );
460            ProxyDirective proxy = m_directive.getProxyDirective();
461            
462            URL url = (URL) line.getValue( HOST_OPTION, null );
463            String username = (String) line.getValue( USERNAME_OPTION, null );
464            String password = (String) line.getValue( PASSWORD_OPTION, null );
465            List values = line.getValues( PROXY_EXCLUDE_OPTION );
466            String[] excludes = (String[]) values.toArray( new String[0] );
467            char[] pswd = toCharArray( password );
468            if( null == proxy )
469            {
470                if( null == url )
471                {
472                    System.out.println( "ERROR: Missing proxy host option." );
473                    return null;
474                }
475                ProxyDirective p = new ProxyDirective( 
476                  url.toString(), excludes, username, pswd );
477                return m_builder.create( p );
478            }
479            else
480            {
481                ProxyDirectiveBuilder builder = new ProxyDirectiveBuilder( proxy );
482                ProxyDirective p = builder.create( url, excludes, username, pswd );
483                return m_builder.create( p );
484            }
485        }
486        
487        private TransitDirective setHost( CommandLine line ) throws Exception
488        {
489            String key = (String) line.getValue( SET_HOST_COMMAND, null );
490            CacheDirective cache = m_directive.getCacheDirective();
491            HostDirective[] hosts = cache.getHostDirectives();
492            HostDirective host = null;
493            for( int i=0; i<hosts.length; i++ )
494            {
495                HostDirective h = hosts[i];
496                if( h.getID().equals( key ) )
497                {
498                    host = h;
499                }
500            }
501            
502            if( null == host )
503            {
504                System.out.println( "ERROR: Host id '" + key + "' not recognized." );
505                return null;
506            }
507            
508            System.out.println( "Updating host: " + key );
509            URL url = (URL) line.getValue( HOST_OPTION, null );
510            int priority = getPriorityValue( line );
511            String index = (String) line.getValue( HOST_INDEX_OPTION, null );
512            String username = (String) line.getValue( USERNAME_OPTION, null );
513            String password = (String) line.getValue( PASSWORD_OPTION, null );
514            boolean enabled = getEnabledFlag( line, host );
515            boolean trusted = getTrustedFlag( line, host );
516            String layout = (String) line.getValue( LAYOUT_OPTION, null );
517            String scheme = (String) line.getValue( HOST_SCHEME_OPTION, null );
518            String prompt = (String) line.getValue( HOST_PROMPT_OPTION, null );
519            
520            HostDirectiveBuilder builder = new HostDirectiveBuilder( host );
521            HostDirective newHost = 
522              builder.create( 
523                priority, url, index, username, toCharArray( password ),
524                enabled, trusted, layout, scheme, prompt );
525            
526            HostDirective[] newHosts = new HostDirective[ hosts.length ];
527            for( int i=0; i<hosts.length; i++ )
528            {   
529                HostDirective h = hosts[i];
530                if( h.getID().equals( key ) )
531                {
532                    newHosts[i] = newHost;
533                }
534                else
535                {
536                    newHosts[i] = h;
537                }
538            }
539            CacheDirectiveBuilder cacheBuilder = new CacheDirectiveBuilder( cache );
540            CacheDirective newCache = cacheBuilder.create( newHosts );
541            return m_builder.create( newCache );
542        }
543        
544        private TransitDirective setLayout( CommandLine line ) throws Exception
545        {
546            String key = (String) line.getValue( SET_LAYOUT_COMMAND, null );
547            CacheDirective cache = m_directive.getCacheDirective();
548            LayoutDirective[] handlers = cache.getLayoutDirectives();
549            LayoutDirective handler = null;
550            for( int i=0; i<handlers.length; i++ )
551            {
552                LayoutDirective c = handlers[i];
553                if( c.getID().equals( key ) )
554                {
555                    handler = c;
556                }
557            }
558    
559            if( null == handler )
560            {
561                System.out.println( "ERROR: Layout id '" + key + "' not recognized." );
562                return null;
563            }
564                
565            System.out.println( "Updating layout: " + key );
566            URI uri = (URI) line.getValue( CODEBASE_OPTION, null );
567            String title = (String) line.getValue( TITLE_OPTION, null );
568                
569            LayoutDirectiveBuilder builder = new LayoutDirectiveBuilder( handler );
570            LayoutDirective newDirective = 
571              builder.create( title, uri, null );
572                
573            LayoutDirective[] newDirectives = new LayoutDirective[ handlers.length ];
574            for( int i=0; i<handlers.length; i++ )
575            {   
576                LayoutDirective d = handlers[i];
577                if( d.getID().equals( key ) )
578                {
579                    newDirectives[i] = newDirective;
580                }
581                else
582                {
583                    newDirectives[i] = d;
584                }
585            }
586            CacheDirectiveBuilder cacheBuilder = new CacheDirectiveBuilder( cache );
587            CacheDirective newCache = cacheBuilder.create( newDirectives );
588            return m_builder.create( newCache );
589        }
590        
591        private TransitDirective processRemove( CommandLine line )
592        {
593            if( line.hasOption( SELECT_HOST_COMMAND ) )
594            {
595                String key = (String) line.getValue( SELECT_HOST_COMMAND, null );
596                System.out.println( "Removing resource host: " + key );
597                CacheDirective cache = m_directive.getCacheDirective();
598                CacheDirectiveBuilder builder = new CacheDirectiveBuilder( cache );
599                try
600                {
601                    CacheDirective newCache = builder.removeHostDirective( key );
602                    return m_builder.create( newCache );
603                }
604                catch( UnknownKeyException e )
605                {
606                    System.out.println( "Unknown host '" + key + "'." );
607                    return null;
608                }
609            }
610            else if( line.hasOption( SELECT_LAYOUT_COMMAND ) )
611            {
612                String key = (String) line.getValue( SELECT_LAYOUT_COMMAND, null );
613                System.out.println( "Removing layout: " + key );
614                CacheDirective cache = m_directive.getCacheDirective();
615                CacheDirectiveBuilder builder = new CacheDirectiveBuilder( cache );
616                try
617                {
618                    CacheDirective newCache = builder.removeLayoutDirective( key );
619                    return m_builder.create( newCache );
620                }
621                catch( UnknownKeyException e )
622                {
623                    System.out.println( "Unknown layout '" + key + "'." );
624                    return null;
625                }
626            }
627            else if( line.hasOption( REMOVE_PROXY_COMMAND ) )
628            {
629                if( null == m_directive.getProxyDirective() )
630                {
631                    System.out.println( "Nothing to remove." );
632                    return null;
633                }
634                else
635                {
636                    System.out.println( "Removing all proxy settings." );
637                    CacheDirective cache = m_directive.getCacheDirective();
638                    return new TransitDirective( null, cache );
639                }
640            }
641            else
642            {
643                throw new IllegalStateException( "Unqualified remove command." );
644            }
645        }
646        
647        private void export( TransitDirective directive )
648        {
649            if( null == directive )
650            {
651                return;
652            }
653            else if( m_directive.equals( directive ) )
654            {
655                System.out.println( "# no change" );
656            }
657            else
658            {
659                URI store = DefaultTransitModel.DEFAULT_PROFILE_URI;
660                URI uri = (URI) m_line.getValue( PROFILE_URI_OPTION, store );
661                System.out.println( "Saving to: " + uri );
662                OutputStream output = null;
663                try
664                {
665                    URL url = buildURL( uri );
666                    output = url.openConnection().getOutputStream();
667                    TransitBuilder builder = new TransitBuilder( m_logger );
668                    builder.write( directive, output );
669                }
670                catch( Exception e )
671                {
672                    final String error = 
673                      "Internal error while attempting to write to the uri: "
674                      + uri;
675                    getLogger().error( error, e );
676                }
677                finally
678                {
679                    if( null != output )
680                    {
681                        try
682                        {
683                            output.close();
684                        }
685                        catch( Exception e )
686                        {
687                            e.printStackTrace();
688                        }
689                    }
690                }
691            }
692        }
693        
694        // ------------------------------------------------------------------------
695        // internal utilities
696        // ------------------------------------------------------------------------
697        
698        private Logger getLogger()
699        {
700            return m_logger;
701        }
702        
703        private char[] toCharArray( String value )
704        {
705            if( null == value )
706            {
707                return null;
708            }
709            else
710            {
711                return value.toCharArray();
712            }
713        }
714        
715        private TransitDirective loadTransitDirective( CommandLine line )
716        {
717            if( line.hasOption( PROFILE_URI_OPTION ) )
718            {
719                URI uri = (URI) line.getValue( PROFILE_URI_OPTION, null );
720                try
721                {
722                    URL url = buildURL( uri );
723                    TransitBuilder builder = new TransitBuilder( m_logger );
724                    return builder.load( url );
725                }
726                catch( FileNotFoundException e )
727                {
728                    final String error = 
729                      "Resource not found: "
730                    + uri;
731                    getLogger().warn( error );
732                    return null;
733                }
734                catch( Exception e )
735                {
736                    final String error = 
737                      "An error occured while attempting to load the transit profile: "
738                      + uri;
739                    getLogger().error( error, e  );
740                    return null;
741                }
742            }
743            else
744            {
745                File prefs = Transit.DPML_PREFS;
746                File config = new File( prefs, "dpml/transit/xmls/standard.xml" );
747                if( config.exists() )
748                {
749                    try
750                    {
751                        URL url = config.toURL();
752                        TransitBuilder builder = new TransitBuilder( m_logger );
753                        return builder.load( url );
754                    }
755                    catch( Exception e )
756                    {
757                        final String error = 
758                          "An error occured while attempting to load the transit profile: "
759                        + config;
760                        getLogger().error( error, e  );
761                        return null;
762                    }
763                }
764                else
765                {
766                    //
767                    // load default profile
768                    //
769                    
770                    return TransitDirective.CLASSIC_PROFILE;
771                }
772            }
773        }
774        
775        private URL buildURL( URI uri ) throws IOException
776        {
777            if( Artifact.isRecognized( uri ) )
778            {
779                return Artifact.createArtifact( uri ).toURL();
780            }
781            else
782            {
783                return uri.toURL();
784            }
785          
786        }
787        
788        private boolean getEnabledFlag( CommandLine line, HostDirective host )
789        {
790            if( line.hasOption( DISABLED_OPTION ) )
791            {
792                return false;
793            }
794            else if( line.hasOption( ENABLED_OPTION ) )
795            {
796                return true;
797            }
798            else
799            {
800                return host.getEnabled();
801            }
802        }
803        
804        private boolean getTrustedFlag( CommandLine line, HostDirective host )
805        {
806            if( line.hasOption( TRUSTED_OPTION ) )
807            {
808                return true;
809            }
810            else if( line.hasOption( UNTRUSTED_OPTION ) )
811            {
812                return false;
813            }
814            else
815            {
816                return host.getTrusted();
817            }
818        }
819        
820        private int getPriorityValue( CommandLine line )
821        {
822            if( line.hasOption( HOST_PRIORITY_OPTION ) )
823            {
824                Number priority = (Number) line.getValue( HOST_PRIORITY_OPTION, new Integer( -1 ) );
825                return priority.intValue();
826            }
827            else
828            {
829                return -1;
830            }
831        }
832        
833        // ------------------------------------------------------------------------
834        // static utilities
835        // ------------------------------------------------------------------------
836        
837        private static final DefaultOptionBuilder OPTION_BUILDER = new DefaultOptionBuilder();
838        private static final ArgumentBuilder ARGUMENT_BUILDER = new ArgumentBuilder();
839        private static final CommandBuilder COMMAND_BUILDER = new CommandBuilder();
840        private static final GroupBuilder GROUP_BUILDER = new GroupBuilder();
841        private static final NumberValidator INTERGER_VALIDATOR = NumberValidator.getIntegerInstance();
842        private static final Set HELP_TOPICS = new HashSet();
843        
844        static
845        {
846            HELP_TOPICS.add( "add" );
847            HELP_TOPICS.add( "set" );
848            HELP_TOPICS.add( "remove" );
849        }
850        
851        private static final Option DIRECTORY_OPTION = 
852            OPTION_BUILDER
853              .withShortName( "dir" )
854              .withDescription( "Directory." )
855              .withRequired( false )
856              .withArgument(
857                ARGUMENT_BUILDER 
858                  .withDescription( "Directory." )
859                  .withName( "path" )
860                  .withMinimum( 1 )
861                  .withMaximum( 1 )
862                  .create() )
863              .create();
864        
865        private static final Option SYSTEM_LIBRARY_OPTION = 
866            OPTION_BUILDER
867              .withShortName( "system" )
868              .withDescription( "Local system repository." )
869              .withRequired( false )
870              .withArgument(
871                ARGUMENT_BUILDER 
872                  .withDescription( "Directory." )
873                  .withName( "dir" )
874                  .withMinimum( 1 )
875                  .withMaximum( 1 )
876                  .create() )
877              .create();
878              
879        private static final Option PROFILE_URI_OPTION = 
880            OPTION_BUILDER
881              .withShortName( "profile" )
882              .withDescription( "Configuration profile uri." )
883              .withRequired( false )
884              .withArgument(
885                ARGUMENT_BUILDER 
886                  .withDescription( "URI path." )
887                  .withName( "uri" )
888                  .withMinimum( 1 )
889                  .withMaximum( 1 )
890                  .withValidator( new URIValidator() )
891                  .create() )
892              .create();
893        
894        private static final Option HELP_COMMAND =
895          COMMAND_BUILDER
896            .withName( "help" )
897            .withDescription( "Print command help." )
898            .create();
899            
900        private static final Option HOST_OPTION = 
901          OPTION_BUILDER
902            .withShortName( "url" )
903            .withDescription( "Host URL." )
904            .withRequired( false )
905            .withArgument(
906              ARGUMENT_BUILDER 
907                .withName( "url" )
908                .withMinimum( 1 )
909                .withMaximum( 1 )
910                .withValidator( new URLValidator() )
911                .create() )
912            .create();
913        
914        private static final Option REQUIRED_HOST_OPTION = 
915          OPTION_BUILDER
916            .withShortName( "url" )
917            .withDescription( "Host URL (required)." )
918            .withRequired( true )
919            .withArgument(
920              ARGUMENT_BUILDER 
921                .withName( "url" )
922                .withMinimum( 1 )
923                .withMaximum( 1 )
924                .withValidator( new URLValidator() )
925                .create() )
926            .create();
927        
928        private static final Option REQUIRED_CODEBASE_OPTION = 
929          OPTION_BUILDER
930            .withShortName( "uri" )
931            .withDescription( "Codebase URI (required)." )
932            .withRequired( true )
933            .withArgument(
934              ARGUMENT_BUILDER 
935                .withName( "uri" )
936                .withMinimum( 1 )
937                .withMaximum( 1 )
938                .withValidator( new URIValidator() )
939                .create() )
940            .create();
941        
942        private static final Option CODEBASE_OPTION = 
943          OPTION_BUILDER
944            .withShortName( "uri" )
945            .withDescription( "Codebase URI." )
946            .withRequired( false )
947            .withArgument(
948              ARGUMENT_BUILDER 
949                .withName( "uri" )
950                .withMinimum( 1 )
951                .withMaximum( 1 )
952                .withValidator( new URIValidator() )
953                .create() )
954            .create();
955        
956        private static final Option TITLE_OPTION = 
957          OPTION_BUILDER
958            .withShortName( "title" )
959            .withDescription( "Title." )
960            .withRequired( false )
961            .withArgument(
962              ARGUMENT_BUILDER 
963                .withName( "name" )
964                .withMinimum( 1 )
965                .withMaximum( 1 )
966                .create() )
967            .create();
968        
969        private static final Option USERNAME_OPTION = 
970          OPTION_BUILDER
971            .withShortName( "username" )
972            .withDescription( "Username." )
973            .withRequired( false )
974            .withArgument(
975              ARGUMENT_BUILDER 
976                .withName( "username" )
977                .withMinimum( 1 )
978                .withMaximum( 1 )
979                .create() )
980            .create();
981        
982        private static final Option PASSWORD_OPTION = 
983          OPTION_BUILDER
984            .withShortName( "password" )
985            .withDescription( "Password." )
986            .withRequired( false )
987            .withArgument(
988              ARGUMENT_BUILDER 
989                .withName( "password" )
990                .withMinimum( 1 )
991                .withMaximum( 1 )
992                .create() )
993            .create();
994    
995        private static final Option HOST_PRIORITY_OPTION = 
996          OPTION_BUILDER
997            .withShortName( "priority" )
998            .withDescription( "Host priority." )
999            .withRequired( false )
1000            .withArgument(
1001              ARGUMENT_BUILDER 
1002                .withName( "int" )
1003                .withMinimum( 1 )
1004                .withMaximum( 1 )
1005                .withValidator( INTERGER_VALIDATOR )
1006                .create() )
1007            .create();
1008    
1009        private static final Option HOST_INDEX_OPTION = 
1010          OPTION_BUILDER
1011            .withShortName( "index" )
1012            .withDescription( "Host index path." )
1013            .withRequired( false )
1014            .withArgument(
1015              ARGUMENT_BUILDER 
1016                .withName( "resource" )
1017                .withMinimum( 1 )
1018                .withMaximum( 1 )
1019                .create() )
1020            .create();
1021            
1022        private static final Option LAYOUT_OPTION = 
1023          OPTION_BUILDER
1024            .withShortName( "layout" )
1025            .withDescription( "Host layout strategy." )
1026            .withRequired( false )
1027            .withArgument(
1028              ARGUMENT_BUILDER 
1029                .withName( "id" )
1030                .withMinimum( 1 )
1031                .withMaximum( 1 )
1032                .create() )
1033            .create();
1034            
1035        private static final Option HOST_SCHEME_OPTION = 
1036          OPTION_BUILDER
1037            .withShortName( "scheme" )
1038            .withDescription( "Host authentication scheme." )
1039            .withRequired( false )
1040            .withArgument(
1041              ARGUMENT_BUILDER 
1042                .withName( "scheme" )
1043                .withMinimum( 1 )
1044                .withMaximum( 1 )
1045                .create() )
1046            .create();
1047            
1048        private static final Option HOST_PROMPT_OPTION = 
1049          OPTION_BUILDER
1050            .withShortName( "prompt" )
1051            .withDescription( "Host authentication prompt." )
1052            .withRequired( false )
1053            .withArgument(
1054              ARGUMENT_BUILDER 
1055                .withName( "prompt" )
1056                .withMinimum( 1 )
1057                .withMaximum( 1 )
1058                .create() )
1059            .create();
1060        
1061        private static final Option TRUSTED_OPTION = 
1062          OPTION_BUILDER
1063            .withShortName( "trusted" )
1064            .withDescription( "Assert as trusted host." )
1065            .withRequired( false )
1066            .create();
1067            
1068        private static final Option UNTRUSTED_OPTION = 
1069          OPTION_BUILDER
1070            .withShortName( "untrusted" )
1071            .withDescription( "Assert as untrusted host." )
1072            .withRequired( false )
1073            .create();
1074        
1075        private static final Group TRUST_GROUP =
1076          GROUP_BUILDER
1077            .withMinimum( 0 )
1078            .withMaximum( 1 )
1079            .withOption( TRUSTED_OPTION )
1080            .withOption( UNTRUSTED_OPTION )
1081            .create();
1082        
1083        private static final Option ENABLED_OPTION = 
1084          OPTION_BUILDER
1085            .withShortName( "enabled" )
1086            .withDescription( "Enable the host." )
1087            .withRequired( false )
1088            .create();
1089            
1090        private static final Option DISABLED_OPTION = 
1091          OPTION_BUILDER
1092            .withShortName( "disabled" )
1093            .withDescription( "Disable the host." )
1094            .withRequired( false )
1095            .create();
1096            
1097        private static final Group ENABLED_GROUP =
1098          GROUP_BUILDER
1099            .withMinimum( 0 )
1100            .withMaximum( 1 )
1101            .withOption( ENABLED_OPTION )
1102            .withOption( DISABLED_OPTION )
1103            .create();
1104        
1105        private static final Option PROXY_EXCLUDE_OPTION = 
1106          OPTION_BUILDER
1107            .withShortName( "excludes" )
1108            .withDescription( "Proxy excludes." )
1109            .withRequired( false )
1110            .withArgument(
1111              ARGUMENT_BUILDER 
1112                .withName( "hosts" )
1113                .withMinimum( 1 )
1114                .withInitialSeparator( ' ' )
1115                .withSubsequentSeparator( ',' )
1116                .create() )
1117            .create();
1118            
1119        private static final Group SET_HANDLER_OPTIONS_GROUP =
1120          GROUP_BUILDER
1121            .withMinimum( 0 )
1122            .withOption( CODEBASE_OPTION )
1123            .withOption( TITLE_OPTION )
1124            .create();
1125        
1126        private static final Group ADD_HANDLER_OPTIONS_GROUP =
1127          GROUP_BUILDER
1128            .withOption( REQUIRED_CODEBASE_OPTION )
1129            .withOption( TITLE_OPTION )
1130            .create();
1131            
1132        private static final Group SET_HOST_OPTIONS_GROUP =
1133          GROUP_BUILDER
1134            .withMinimum( 0 )
1135            .withOption( HOST_OPTION )
1136            .withOption( USERNAME_OPTION )
1137            .withOption( PASSWORD_OPTION )
1138            .withOption( HOST_PRIORITY_OPTION )
1139            .withOption( HOST_INDEX_OPTION )
1140            .withOption( ENABLED_GROUP )
1141            .withOption( TRUST_GROUP )
1142            .withOption( LAYOUT_OPTION )
1143            .withOption( HOST_SCHEME_OPTION )
1144            .withOption( HOST_PROMPT_OPTION )
1145            .create();
1146        
1147        private static final Group ADD_HOST_OPTIONS_GROUP =
1148          GROUP_BUILDER
1149            .withMinimum( 0 )
1150            .withOption( REQUIRED_HOST_OPTION )
1151            .withOption( USERNAME_OPTION )
1152            .withOption( PASSWORD_OPTION )
1153            .withOption( HOST_PRIORITY_OPTION )
1154            .withOption( HOST_INDEX_OPTION )
1155            .withOption( DISABLED_OPTION )
1156            .withOption( TRUSTED_OPTION )
1157            .withOption( LAYOUT_OPTION )
1158            .withOption( HOST_SCHEME_OPTION )
1159            .withOption( HOST_PROMPT_OPTION )
1160            .create();
1161        
1162        private static final Group PROXY_OPTIONS_GROUP =
1163          GROUP_BUILDER
1164            .withMinimum( 0 )
1165            .withOption( HOST_OPTION )
1166            .withOption( USERNAME_OPTION )
1167            .withOption( PASSWORD_OPTION )
1168            .withOption( PROXY_EXCLUDE_OPTION )
1169            .create();
1170        
1171        private static final Group CACHE_OPTIONS_GROUP =
1172          GROUP_BUILDER
1173            .withMinimum( 0 )
1174            .withOption( DIRECTORY_OPTION )
1175            .withOption( LAYOUT_OPTION )
1176            .create();
1177        
1178        private static final Group SYSTEM_OPTIONS_GROUP =
1179          GROUP_BUILDER
1180            .withMinimum( 0 )
1181            .withOption( DIRECTORY_OPTION )
1182            .withOption( LAYOUT_OPTION )
1183            .create();
1184        
1185        private static final Option PROXY_COMMAND =
1186          COMMAND_BUILDER
1187            .withName( "proxy" )
1188            .withDescription( "Select proxy settings." )
1189            .withChildren( PROXY_OPTIONS_GROUP )
1190            .create();
1191        
1192        private static final Option SET_CACHE_COMMAND =
1193          COMMAND_BUILDER
1194            .withName( "cache" )
1195            .withDescription( "Select cache settings." )
1196            .withChildren( CACHE_OPTIONS_GROUP )
1197            .create();
1198        
1199        private static final Option SET_SYSTEM_COMMAND =
1200          COMMAND_BUILDER
1201            .withName( "system" )
1202            .withDescription( "Select system repository settings." )
1203            .withChildren( SYSTEM_OPTIONS_GROUP )
1204            .create();
1205        
1206        private static final Option ADD_HOST_COMMAND =
1207          COMMAND_BUILDER
1208            .withName( "host" )
1209            .withDescription( "Add a new resource host." )
1210            .withChildren( ADD_HOST_OPTIONS_GROUP )
1211            .withArgument(
1212              ARGUMENT_BUILDER 
1213                .withName( "id" )
1214                .withMinimum( 1 )
1215                .withMaximum( 1 )
1216                .create() )
1217            .create();
1218    
1219        private static final Option SET_HOST_COMMAND =
1220          COMMAND_BUILDER
1221            .withName( "host" )
1222            .withDescription( "Resource host selection." )
1223            .withChildren( SET_HOST_OPTIONS_GROUP )
1224            .withArgument(
1225              ARGUMENT_BUILDER 
1226                .withName( "id" )
1227                .withMinimum( 1 )
1228                .withMaximum( 1 )
1229                .create() )
1230            .create();
1231    
1232        private static final Option SET_LAYOUT_COMMAND =
1233          COMMAND_BUILDER
1234            .withName( "layout" )
1235            .withDescription( "Layout scheme selection." )
1236            .withChildren( SET_HANDLER_OPTIONS_GROUP )
1237            .withArgument(
1238              ARGUMENT_BUILDER 
1239                .withName( "id" )
1240                .withMinimum( 1 )
1241                .withMaximum( 1 )
1242                .create() )
1243            .create();
1244    
1245        private static final Option SELECT_HOST_COMMAND =
1246          COMMAND_BUILDER
1247            .withName( "host" )
1248            .withDescription( "Resource host selection." )
1249            .withArgument(
1250              ARGUMENT_BUILDER 
1251                .withName( "id" )
1252                .withMinimum( 1 )
1253                .withMaximum( 1 )
1254                .create() )
1255            .create();
1256    
1257        private static final Option SELECT_LAYOUT_COMMAND =
1258          COMMAND_BUILDER
1259            .withName( "layout" )
1260            .withDescription( "Layout scheme selection." )
1261            .withArgument(
1262              ARGUMENT_BUILDER 
1263                .withName( "id" )
1264                .withMinimum( 1 )
1265                .withMaximum( 1 )
1266                .create() )
1267            .create();
1268    
1269        private static final Option ADD_LAYOUT_COMMAND =
1270          COMMAND_BUILDER
1271            .withName( "layout" )
1272            .withDescription( "Add a new layout." )
1273            .withChildren( ADD_HANDLER_OPTIONS_GROUP )
1274            .withArgument(
1275              ARGUMENT_BUILDER 
1276                .withName( "id" )
1277                .withMinimum( 1 )
1278                .withMaximum( 1 )
1279                .create() )
1280            .create();
1281            
1282        private static final Option REMOVE_PROXY_COMMAND =
1283          COMMAND_BUILDER
1284            .withName( "proxy" )
1285            .withDescription( "Delete proxy settings." )
1286            .create();
1287            
1288        private static final Group ADD_OPTIONS_GROUP =
1289          GROUP_BUILDER
1290            .withMinimum( 1 )
1291            .withMinimum( 1 )
1292            .withOption( ADD_HOST_COMMAND )
1293            .withOption( ADD_LAYOUT_COMMAND )
1294            .create();
1295    
1296        private static final Group SET_OPTIONS_GROUP =
1297          GROUP_BUILDER
1298            .withMinimum( 1 )
1299            .withMinimum( 1 )
1300            .withOption( PROXY_COMMAND )
1301            .withOption( SET_CACHE_COMMAND )
1302            .withOption( SET_SYSTEM_COMMAND )
1303            .withOption( SET_HOST_COMMAND )
1304            .withOption( SET_LAYOUT_COMMAND )
1305            .create();
1306        
1307        private static final Group REMOVE_OPTIONS_GROUP =
1308          GROUP_BUILDER
1309            .withMinimum( 1 )
1310            .withMinimum( 1 )
1311            .withOption( SELECT_HOST_COMMAND )
1312            .withOption( SELECT_LAYOUT_COMMAND )
1313            .withOption( REMOVE_PROXY_COMMAND )
1314            .create();
1315        
1316        private static final Option ADD_COMMAND =
1317          COMMAND_BUILDER
1318            .withName( "add" )
1319            .withChildren( ADD_OPTIONS_GROUP )
1320            .create();
1321        
1322        private static final Option SET_COMMAND =
1323          COMMAND_BUILDER
1324            .withName( "set" )
1325            .withDescription( "Set an configuration aspect." )
1326            .withChildren( SET_OPTIONS_GROUP )
1327            .create();
1328        
1329        private static final Option REMOVE_COMMAND =
1330          COMMAND_BUILDER
1331            .withName( "remove" )
1332            .withChildren( REMOVE_OPTIONS_GROUP )
1333            .create();
1334        
1335        private static final Option INFO_COMMAND =
1336          COMMAND_BUILDER
1337            .withName( "info" )
1338            .withDescription( "List configuration." )
1339            .create();
1340    
1341        private static final Option REVERT_COMMAND =
1342          COMMAND_BUILDER
1343            .withName( "revert" )
1344            .withDescription( "Set configuration to default." )
1345            .create();
1346    
1347        private static final Option LOAD_COMMAND =
1348          COMMAND_BUILDER
1349            .withName( "load" )
1350            .withDescription( "Load a transit plugin." )
1351            .withArgument(
1352              ARGUMENT_BUILDER 
1353                .withName( "uri" )
1354                .withMinimum( 1 )
1355                .withMaximum( 1 )
1356                .withValidator( new URIValidator() )
1357                .create() )
1358            .create();
1359        
1360        private static final Option ARGUMENTS = 
1361            ARGUMENT_BUILDER
1362              .withName( "args" )
1363              .create();
1364    
1365        private static final Group COMMAND_GROUP =
1366          GROUP_BUILDER
1367            .withOption( INFO_COMMAND )
1368            .withOption( ADD_COMMAND )
1369            .withOption( SET_COMMAND )
1370            .withOption( REMOVE_COMMAND )
1371            .withOption( REVERT_COMMAND )
1372            .withOption( LOAD_COMMAND )
1373            .withOption( HELP_COMMAND )
1374            .withMinimum( 1 )
1375            .withMaximum( 1 )
1376            .create();
1377        
1378        private static final Group OPTIONS_GROUP =
1379          GROUP_BUILDER
1380            .withName( "command" )
1381            .withOption( PROFILE_URI_OPTION )
1382            .withOption( COMMAND_GROUP )
1383            .withOption( ARGUMENTS )
1384            .withMinimum( 0 )
1385            .create();
1386    
1387        private static CommandLine getCommandLine( Logger logger, String[] args )
1388        {
1389            try
1390            {
1391                // parse the command line arguments
1392            
1393                Parser parser = new Parser();
1394                parser.setGroup( OPTIONS_GROUP );
1395                return parser.parse( args );
1396            }
1397            catch( OptionException e )
1398            {
1399                logger.error( e.getMessage() );
1400                return null;
1401            }
1402        }
1403        
1404        private static void processHelp() throws IOException
1405        {
1406            processGeneralHelp( OPTIONS_GROUP );
1407        }
1408        
1409        private static void processGeneralHelp( Group group ) throws IOException
1410        {
1411            HelpFormatter formatter = new HelpFormatter( 
1412              HelpFormatter.DEFAULT_GUTTER_LEFT, 
1413              HelpFormatter.DEFAULT_GUTTER_CENTER, 
1414              HelpFormatter.DEFAULT_GUTTER_RIGHT, 
1415              100, 50 );
1416            
1417            formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_GROUP_OUTER );
1418            formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION );
1419            formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED );
1420            
1421            formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_OPTIONAL );
1422            formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_GROUP_OUTER );
1423            formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION );
1424            formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_OPTIONAL );
1425            formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED );
1426            formatter.getFullUsageSettings().remove( DisplaySetting.DISPLAY_PARENT_CHILDREN );
1427            
1428            formatter.getLineUsageSettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION );
1429            formatter.getLineUsageSettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED );
1430            formatter.getLineUsageSettings().remove( DisplaySetting.DISPLAY_PARENT_CHILDREN );
1431            formatter.getLineUsageSettings().remove( DisplaySetting.DISPLAY_GROUP_EXPANDED );
1432            
1433            formatter.setGroup( group );
1434            formatter.setShellCommand( "transit" );
1435            formatter.print();
1436        }
1437    }
1438